#pragma once

#include "GlutStuff.h"
#include "GlutDemoApplication.h"

#define PlatformDemoApplication GlutDemoApplication

#include "btBulletDynamicsCommon.h"
#include "LinearMath/btAlignedObjectArray.h"

#include "GLDebugDrawer.h"

class ISimulation;

class Simulator : public PlatformDemoApplication
{
public:
	Simulator(void);
	virtual ~Simulator(void);

	bool init(HWND hWnd, ISimulation * simulation);
	void exit();

	void setScreenSize(int x, int y);
	void updateScreen();
			
	void play()
	{
		m_idle = false;	//	defined in DemoApplication.
	}
	void nextStep()
	{
		if(!isPlaying())
			clientMoveAndDisplay();
	}
	bool isPlaying() const
	{
		return !m_idle;	//	defined in DemoApplication.
	}
	void pause()
	{
		m_idle = true;
	}

	void restart()
	{
		clientResetScene();
	}

	void zoomIn(float step = 0)
	{
		if(step > 0)
			m_zoomStepSize = step;

		DemoApplication::zoomIn();
	}

	void zoomOut(float step = 0)
	{
		if(step > 0)
			m_zoomStepSize = step;

		DemoApplication::zoomOut();
	}

	bool isTextureEnabled() const
	{
		return m_shapeDrawer->hasTextureEnabled();
	}
	void enableTexture(bool enable)
	{
		m_shapeDrawer->enableTexture(enable);
	}

	bool isDebugMessageEnabled() const
	{
		return (m_debugMode & btIDebugDraw::DBG_NoHelpText) != 0;
	}

	void enableDebugMessage(bool enable)
	{
		if (enable)
			m_debugMode |= btIDebugDraw::DBG_NoHelpText;
		else
			m_debugMode = m_debugMode & (~btIDebugDraw::DBG_NoHelpText);

		if (getDynamicsWorld() && getDynamicsWorld()->getDebugDrawer())
			getDynamicsWorld()->getDebugDrawer()->setDebugMode(m_debugMode);
	}

	bool isWireFrameEnabled() const
	{
		return (m_debugMode & btIDebugDraw::DBG_DrawWireframe) != 0;
	}

	void enableWireFrame(bool enable)
	{
		if (enable)
			m_debugMode |= btIDebugDraw::DBG_DrawWireframe;
		else
			m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawWireframe);

		if (getDynamicsWorld() && getDynamicsWorld()->getDebugDrawer())
			getDynamicsWorld()->getDebugDrawer()->setDebugMode(m_debugMode);
	}

	bool isShowAABBEnabled() const
	{
		return (m_debugMode & btIDebugDraw::DBG_DrawAabb) != 0;
	}

	void enableShowAABB(bool enable)
	{
		if (enable)
			m_debugMode |= btIDebugDraw::DBG_DrawAabb;
		else
			m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawAabb);

		if (getDynamicsWorld() && getDynamicsWorld()->getDebugDrawer())
			getDynamicsWorld()->getDebugDrawer()->setDebugMode(m_debugMode);
	}

	bool isShowContactEnabled() const
	{
		return (m_debugMode & btIDebugDraw::DBG_DrawContactPoints) != 0;
	}

	void enableShowContact(bool enable)
	{
		if (enable)
			m_debugMode |= btIDebugDraw::DBG_DrawContactPoints;
		else
			m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawContactPoints);

		if (getDynamicsWorld() && getDynamicsWorld()->getDebugDrawer())
			getDynamicsWorld()->getDebugDrawer()->setDebugMode(m_debugMode);
	}

protected:
	virtual void initPhysics();
	virtual void exitPhysics();
	virtual void clientMoveAndDisplay();
	virtual void displayCallback();

private:
	ISimulation * m_simulation;

	HWND m_hWnd;
	HDC	m_hDC;
	HGLRC m_hRC;

	GLDebugDrawer m_debugDraw;
};

class ISimulation
{
public:
	virtual ~ISimulation() {}

	virtual btDynamicsWorld * initPhysics(Simulator & simulator) = 0;
	virtual void exitPhysics() = 0;
};
